package api

import (
	"fmt"
	"goadmin/conf"
	"goadmin/dao"
	"goadmin/model"
	"goadmin/utils"
	"path/filepath"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
)

type _fileRes struct {
	Url  string `json:"url"`
	Name string `json:"name"`
	Type int    `json:"type"`
}

type _fileUploadReq struct {
	Name string `form:"name" json:"name" binding:"required"`
	Type string `form:"type" json:"type" binding:"required"`
}

// @Tags file
// @Summary File find by hash
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param hash query string true "Hash"
// @Success 200 {object} resBody{data=_fileRes}
// @Router /api/files [get]
func FileFindHash(c *gin.Context) {
	var query struct {
		Hash string `form:"hash" binding:"required"`
	}
	if err := c.ShouldBindQuery(&query); err != nil {
		resInvalidQuery(c)
		return
	}

	file, err := dao.GetFileByHash(strings.TrimSpace(strings.ToLower(query.Hash)))
	if err != nil {
		resFai(c, "Failed to get file")
		return
	}

	resSuc(c, _fileRes{
		Url:  conf.File.UploadPath + file.Name,
		Name: file.OriginalName,
		Type: file.Type,
	})
}

// @Tags file
// @Summary File upload
// @Accept multipart/form-data
// @Produce json
// @Security ApiKeyAuth
// @Param name formData string true "Name"
// @Param hash formData string true "Hash"
// @Param type formData string true "Type" Enums(image, video, audio, file)
// @Param file formData file true "File"
// @Success 200 {object} resBody{data=_fileRes}
// @Router /api/files [post]
func FileUpload(c *gin.Context) {
	var formData _fileUploadReq
	if err := c.ShouldBindWith(&formData, binding.Form); err != nil {
		resInvalidForm(c)
		return
	}

	file, err := c.FormFile("file")
	if err != nil {
		resFai(c, "Upload failed")
		return
	}
	if file.Size > conf.File.MaxMB*1024*1024 {
		resFai(c, "Upload failed, file size exceeds limit")
		return
	}

	hashValue, err := utils.HashFile(file)
	if err != nil {
		resFai(c, "Upload failed,hash error")
		return
	}

	fileOriginalName := formData.Name
	tp := utils.GetFileType(formData.Type)
	ext := filepath.Ext(fileOriginalName)
	if !utils.CompareFileTypeExt(tp, ext) {
		resFai(c, "Upload failed, file type error")
		return
	}

	if f, err := dao.GetFileByHash(hashValue); err == nil {
		// 文件已存在, 直接返回
		resSuc(c, _fileRes{
			Url:  conf.File.UploadPath + f.Name,
			Name: f.OriginalName,
			Type: f.Type,
		})
		return
	}
	// 建立当日文件夹 YYYYMMDD
	y, m, d := time.Now().Date()
	fileSaveName := fmt.Sprintf("%d/%02d/%02d/%s", y, m, d, hashValue+ext)
	tarPath := conf.File.UploadPath + fileSaveName
	err = c.SaveUploadedFile(file, tarPath)
	if err != nil {
		resFai(c, "Upload failed, file save error")
		return
	}

	userId := c.GetUint("user_id")
	err = dao.InsertFile(&model.File{
		UserId:       userId,
		OriginalName: fileOriginalName,
		Name:         fileSaveName,
		Hash:         hashValue,
		Type:         tp,
	})
	if err != nil {
		resFai(c, "Upload failed, database error")
		return
	}

	resSuc(c, _fileRes{
		Url:  tarPath,
		Name: fileOriginalName,
		Type: tp,
	})
}
